package cn.net.autocode.platform.function;

import cn.net.autocode.core.bean.ResultT;
import cn.net.autocode.core.utils.TreeUtils;
import cn.net.autocode.dbManager.Dao;
import cn.net.autocode.platform.design.handle.AutoCodeHandle;
import cn.net.autocode.platform.design.vo.AppInfo;
import cn.net.autocode.platform.function.service.FuncServ;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

@RestController("platformFuncTree")
@RequestMapping("/platform/funcTree")
public class FuncTree {

    private final Dao dictDao;
    private final FuncServ funcServ;

    public FuncTree(@Qualifier("dictDao") Dao dictDao, FuncServ funcServ) {
        this.dictDao = dictDao;
        this.funcServ = funcServ;
    }


    @RequestMapping("load")
    public ResultT load(){
        JSONArray tree = funcServ.queryPageTree();
        return ResultT.success(tree);
    }

    @RequestMapping("del")
    @Transactional
    public ResultT del(@RequestBody JSONObject jsonObject){
        String type = jsonObject.getString("type");
        switch (type) {
            case "page" -> {
                dictDao.executeUpdate("delete from ac_page_versions where page_id = ?", jsonObject.getString("id"));
                dictDao.executeUpdate("delete from ac_page where id = ?", jsonObject.getString("id"));
            }
            case "application" -> {
                int num = dictDao.queryValue("select count(*) from ac_page where category_code=?", Integer.class, jsonObject.getString("code"));
                if (num > 0) {
                    return ResultT.fail("目录下存在子数据，请先删除子数据！");
                } else {
                    dictDao.executeUpdate("delete from ac_category where code = ? and type='application' ", jsonObject.getString("code"));
                }
            }
            case "category" -> {
                int num = dictDao.queryValue("select count(*) from ac_category where parent_code=?", Integer.class, jsonObject.getString("code"));
                if (num > 0) {
                    return ResultT.fail("目录下存在子数据，请先删除子数据！");
                } else {
                    dictDao.executeUpdate("delete from ac_category where code = ? and type='category'", jsonObject.getString("code"));
                }
            }
        }
        return ResultT.success();
    }


    @RequestMapping("syncFunc")
    public ResultT syncFunc(){
        funcServ.syncFunc();

        return ResultT.success();
    }

    @RequestMapping("syncFuncAndRelease")
    public ResultT syncFuncAndRelease(){
        funcServ.syncFunc();
        funcServ.batchRelease();
        return ResultT.success();
    }


    @RequestMapping("selectPages")
    public ResultT selectPages(){
        JSONArray tree = funcServ.queryPageTree();
        return ResultT.success(tree);
    }

    @RequestMapping("downLoadRealsePage")
    public ResponseEntity<byte[]> downLoadRealsePage(@RequestBody JSONArray param){
        //授权信息
        AppInfo appInfo = AutoCodeHandle.getAppInfo();
        if(appInfo==null){
            throw new RuntimeException("没有设置授权信息，请登陆(https://autocode.net.cn)下载license.lic授权文件，下载后复制到resources目录下，重启应用！");
        }

        JSONObject acSetting = dictDao.queryJSON("select appid from ac_setting");
        if(acSetting.isEmpty() || !appInfo.getAppid().equals(acSetting.getString("appid"))){
            dictDao.execute("delete from ac_page_versions");
            dictDao.executeUpdate("update ac_page set max_version=?,version=?",-1,-1);
            if (acSetting.isEmpty()){
                dictDao.executeUpdate("insert into ac_setting(appid) values(?)",appInfo.getAppid());
            }else{
                dictDao.executeUpdate("update ac_setting set appid=?",appInfo.getAppid());
            }
        }

        //下载页面信息
        List<String> pageList = new ArrayList<>();
        this.parase(pageList,param);

        if (pageList.isEmpty()){
            throw new RuntimeException("至少选择一个要下载的页面！");
        }
        JSONArray pageArrays = dictDao.queryJSONArray("select * from ac_page where id in (?)",pageList);
        JSONArray pageVersions = dictDao.queryJSONArray("select t2.* from ac_page t1,ac_page_versions t2 where t1.id in (?) and t1.id=t2.page_id and t2.version>=t1.version and t2.version<=t1.max_version",pageList);
        int len2=pageArrays.size();
        for(int i=0;i<len2;i++){
            JSONObject page = pageArrays.getJSONObject(i);
            page.put("parentId","application_"+page.getString("categoryCode"));
            page.put("type","page");
            JSONArray children = new JSONArray();
            int len3 = pageVersions.size();
            for(int j=0;j<len3;j++){
                JSONObject pageVersion = pageVersions.getJSONObject(j);
                String pageId = pageVersion.getString("pageId");
                if(pageId.equals(page.getString("id"))){
                    children.add(pageVersion);
                }
            }
            if (children.isEmpty()){
                page.put("children",new JSONArray());
            }else {
                page.put("children",pageVersions);
            }
        }

        JSONArray arrays = new JSONArray();
        JSONArray categorys = dictDao.queryJSONArray("select * from ac_category where type='category' order by code");
        for(int i=0;i<categorys.size();i++){
            JSONObject category = categorys.getJSONObject(i);
            category.put("id","category_"+category.getString("code"));
            category.put("parentId", "0");
        }
        arrays.addAll(categorys);
        JSONArray applications = dictDao.queryJSONArray("select * from ac_category t1 where type='application' and exists(select 1 from ac_page t2 where t1.code=t2.category_code and t2.id in (?)) order by code",pageList);
        arrays.addAll(applications);
        int len=applications.size();
        for(int i=0;i<len;i++){
            JSONObject application = applications.getJSONObject(i);
            application.put("id","application_"+application.getString("code"));
            application.put("parentId","category_"+application.getString("parentCode"));
        }

        arrays.addAll(pageArrays);
        JSONArray treeArray = TreeUtils.commonTree(arrays);

        JSONArray downloadPage = new JSONArray();
        for(int i=0;i<treeArray.size();i++){
            JSONObject json = treeArray.getJSONObject(i);
            if (json.getJSONArray("children")!=null && !json.getJSONArray("children").isEmpty()){
                downloadPage.add(json);
            }
        }
        //组合下载内容
        JSONObject downLoadJSON = new JSONObject();
        downLoadJSON.put("downloadPage",downloadPage);
        downLoadJSON.put("appid",appInfo.getAppid());

        //获取页面最新及已发布的内容
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String fileName = "lg_"+ LocalDateTime.now().format(formatter)+".lg";
        byte[] encodeBytes = Base64.getEncoder().encode(downLoadJSON.toJSONString().getBytes(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.add("file-name", URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        return new ResponseEntity<>(encodeBytes, headers, HttpStatus.OK);
    }

    @RequestMapping("upLoadRealsePage")
    @Transactional
    @ResponseBody
    public ResultT upLoadRealsePage(@RequestParam MultipartFile[] file) throws IOException {

        //获取文件信息
        if (file==null||file.length==0){
            return  ResultT.fail("请选择需要上传的文件信息！");
        }

        byte[] bytes = Base64.getDecoder().decode(new String(file[0].getBytes(),StandardCharsets.UTF_8));

        JSONObject fileJSON = JSON.parseObject(bytes);
        String appid = fileJSON.getString("appid");
        if (appid!=null && !appid.isBlank()){
            JSONObject acSetting = dictDao.queryJSON("select appid from ac_setting");
            if(acSetting.isEmpty() || !appid.equals(acSetting.getString("appid"))){
                throw new RuntimeException("appid不一致，不能进行代码导入！");
            }
        }

        JSONArray tree = fileJSON.getJSONArray("downloadPage");
        for(int i=0;i<tree.size();i++){
            JSONObject category = tree.getJSONObject(i);
            int updateNum = dictDao.executeUpdate("update ac_category set label=?,parent_code=? where code=? and type=?",category.getString("label"),category.getString("parentCode"),category.getString("code"),category.getString("type"));
            if(updateNum==0){
                dictDao.executeUpdate("insert into ac_category(label,parent_code,code,type) values(?,?,?,?)",category.getString("label"),category.getString("parentCode"),category.getString("code"),category.getString("type"));
            }

            JSONArray applications = category.getJSONArray("children");
            for(int j=0;j<applications.size();j++){
                JSONObject application = applications.getJSONObject(j);
                int updateNum2 = dictDao.executeUpdate("update ac_category set label=?,parent_code=? where code=? and type=?",application.getString("label"),application.getString("parentCode"),application.getString("code"),application.getString("type"));
                if(updateNum2==0){
                    dictDao.executeUpdate("insert into ac_category(label,parent_code,code,type) values(?,?,?,?)",application.getString("label"),application.getString("parentCode"),application.getString("code"),application.getString("type"));
                }

                JSONArray pages = application.getJSONArray("children");
                for(int k=0;k<pages.size();k++){
                    JSONObject page = pages.getJSONObject(k);
                    int updateNum3 = dictDao.executeUpdate("update ac_page set label=?,version=?,max_version=? where id=?",page.getString("label"),page.getIntValue("version"),page.getIntValue("maxVersion"),page.getString("id"));
                    if(updateNum3==0){
                        dictDao.executeUpdate("insert into ac_page(label,id,category_code,code,app_type,version,max_version) values(?,?,?,?,?,?,?)",page.getString("label"),page.getString("id"),page.getString("categoryCode"),page.getString("code"),page.getString("appType"),page.getIntValue("version"),page.getIntValue("maxVersion"));
                    }

                    JSONArray pageVersions = page.getJSONArray("children");
                    for(int z=0;z<pageVersions.size();z++){
                        JSONObject pageVersion = pageVersions.getJSONObject(z);
                        int updateNum4 = dictDao.queryValue("select count(*) from ac_page_versions where page_id=? and version=?",Integer.class,pageVersion.getString("pageId"),pageVersion.getIntValue("version"));
                        if(updateNum4==0){
                            dictDao.createJSON(pageVersion,"ac_page_versions");
                        }
                    }
                }
            }
        }
        return ResultT.success();
    }


    private void parase(List<String> contain,JSONArray param){
        for(int i=0;i<param.size();i++){
            JSONObject json = param.getJSONObject(i);
            String type = json.getString("type");
            if(type.equals("page")){
                contain.add(json.getString("id"));
            }else{
                JSONArray children = json.getJSONArray("children");
                if(children!=null){
                    this.parase(contain,children);
                }
            }
        }
    }

}
